package com.lock.starter.elastic.config;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.BeansException;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.Objects;
import java.util.stream.Stream;

@Configuration
@ConditionalOnClass({Mono.class, Flux.class, RestHighLevelClient.class})
@ConditionalOnProperty(value = {"elasticsearch.hosts", "elasticsearch.timeout"})
public class ElasticSearchAutoConfiguration implements ApplicationContextAware {

    private String hosts;

    private Integer timeout;

    /**
     * 创建客户端连接，支持集群
     */
    private RestHighLevelClient restHighLevelClient() {
        return new RestHighLevelClient(
                // 利用Builder构建器来初始化，接收HttpHost数组
                RestClient.builder(
                        // 将地址以 , 分割得到其中的每个地址
                        Stream.of(StringUtils.split(hosts, ","))
                                // 将单个地址封装为HttpHost对象
                                .map(HttpHost::create)
                                // 转为HttpHost数组
                                .toArray(HttpHost[]::new)
                ).setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
                    @Override
                    public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
                        return httpClientBuilder
                                .setDefaultRequestConfig(RequestConfig.custom()
                                        .setSocketTimeout(30000) // 套接字超时Socket timeout (default is 30000 ms)
                                        .setConnectTimeout(5000 * timeout) // 连接超时Connection timeout (default is 5000 ms)
                                        .setConnectionRequestTimeout(5000 * timeout) // 连接请求超时Connection request timeout (default is 5000 ms)
                                        .build());
                    }
                })
        );
    }

    /**
     * 将自定义的库（包）扫描类注册到IOC容器中
     */
    @Bean
    public RepositoryScanner repositoryScanner() {
        return new RepositoryScanner(restHighLevelClient());
    }

    /**
     * 读取配置文件中的指定属性，并使之生效
     *
     * @param applicationContext applicationContext
     * @throws BeansException BeansException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.hosts = applicationContext.getEnvironment().getProperty("elasticsearch.hosts");
        this.timeout = Integer.parseInt(Objects.requireNonNull(applicationContext.getEnvironment().getProperty("elasticsearch.timeout")));
    }
}
